<?php

declare(strict_types=1);

namespace App\Middleware;

use Hyperf\Context\Context;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Hyperf\Redis\Redis;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class BackendAuthMiddleware implements MiddlewareInterface
{
    protected ContainerInterface $container;

    protected RequestInterface $request;

    protected HttpResponse $response;

    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->response = $response;
        $this->request = $request;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $path = $this->request->getPathInfo();
        $isPublic = str_starts_with(basename($path), 'public');
        Context::set('clientIp', getClientIp());
        if (in_array($path, ['/index/login', '/index/logout']) || $isPublic) {
            return $handler->handle($request);
        } elseif ($this->request->hasHeader('token') && $this->request->header('token') != '') {
            Context::set('token', $this->request->header('token'));
            try {
                $redis = $this->container->get(Redis::class);
                $tokenInfo = $redis->hGetAll('admin:token:' . $this->request->header('token'));
                if ($tokenInfo) {
                    Context::set('userId', (int)$tokenInfo['userId']);
                    Context::set('userName', $tokenInfo['userName']);
                    Context::set('userNick', $tokenInfo['userNick']);
                    Context::set('roleId', (int)$tokenInfo['roleId']);
                    Context::set('lastTime', (int)$tokenInfo['lastTime']);
                    Context::set('lastIp', (int)$tokenInfo['lastIp']);
                    return $handler->handle($request);
                }
            } catch (ContainerExceptionInterface|NotFoundExceptionInterface|\RedisException $e) {
                return $this->response->json(
                    [
                        'code' => 500,
                        'msg' => '系统繁忙',
                    ]
                );
            }
        }
        return $this->response->json(
            [
                'code' => 403,
                'msg' => '请登录后操作',
            ]
        );
    }
}
